vulkan: Put the vertex buffer into the render object
authorBenjamin Otte <otte@redhat.com>
Sat, 8 Jul 2023 07:04:12 +0000 (09:04 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 16 Jul 2023 10:13:00 +0000 (12:13 +0200)
Renderpasses get recreated every frame, but we keep render objects
around. So if we keep the vertex buffer in the render object, we can
also keep it around and just reuse it.

Also, we only need one buffer for all the render passes, which is
another bonus.

The initial buffer size is chosen at 128kB. Maximized Nautilus,
gnome-text-editor with an open file and widget-factory take ~100kB when
doing a full redraw. Other apps are between 30-50kB usually.

So I chose a value that is not too big, but catches ~90% of cases.

gsk/vulkan/gskvulkanbuffer.c
gsk/vulkan/gskvulkanbufferprivate.h
gsk/vulkan/gskvulkanoffscreenop.c
gsk/vulkan/gskvulkanrender.c
gsk/vulkan/gskvulkanrenderpass.c
gsk/vulkan/gskvulkanrenderpassprivate.h

index a2e850da22b97775dab6bf479e27ebc7ef7e3cb2..a89dfddcdf0849614b95f1562f70d4550069e5ef 100644 (file)
@@ -103,6 +103,12 @@ gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self)
   return self->vk_buffer;
 }
 
+gsize
+gsk_vulkan_buffer_get_size (GskVulkanBuffer *self)
+{
+  return self->size;
+}
+
 guchar *
 gsk_vulkan_buffer_map (GskVulkanBuffer *self)
 {
index 9c51586216cd1d61d074a5964963621469f8d07b..009e79da528fd82b4cdf8c3dce97cd46f6ba8f0f 100644 (file)
@@ -23,6 +23,7 @@ GskVulkanBuffer *       gsk_vulkan_buffer_new_map                       (GdkVulk
 void                    gsk_vulkan_buffer_free                          (GskVulkanBuffer        *buffer);
 
 VkBuffer                gsk_vulkan_buffer_get_buffer                    (GskVulkanBuffer        *self);
+gsize                   gsk_vulkan_buffer_get_size                      (GskVulkanBuffer        *self);
 
 guchar *                gsk_vulkan_buffer_map                           (GskVulkanBuffer        *self);
 void                    gsk_vulkan_buffer_unmap                         (GskVulkanBuffer        *self);
index 7be22444dc32ad2e6e6e39c4e5ac5d8b72270481..b2fc4f4f037d5bd5f8a09f47af6d7d5f9590ebee 100644 (file)
@@ -57,7 +57,9 @@ static gsize
 gsk_vulkan_offscreen_op_count_vertex_data (GskVulkanOp *op,
                                            gsize        n_bytes)
 {
-  return n_bytes;
+  GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op;
+
+  return gsk_vulkan_render_pass_count_vertex_data (self->render_pass, n_bytes);
 }
 
 static void
@@ -66,6 +68,9 @@ gsk_vulkan_offscreen_op_collect_vertex_data (GskVulkanOp         *op,
                                              GskVulkanRender     *render,
                                              guchar              *data)
 {
+  GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op;
+
+  gsk_vulkan_render_pass_collect_vertex_data (self->render_pass, render, data);
 }
 
 static void
index f1c0bf9e621565acb4089164b48d56509cfe3088..f997ab0443e4fb9afae9eda33ed87ea39d9379cb 100644 (file)
@@ -16,6 +16,7 @@
 #include "gdk/gdkvulkancontextprivate.h"
 
 #define DESCRIPTOR_POOL_MAXITEMS 50000
+#define VERTEX_BUFFER_SIZE_STEP 128 * 1024 /* 128kB */
 
 #define GDK_ARRAY_NAME gsk_descriptor_image_infos
 #define GDK_ARRAY_TYPE_NAME GskDescriptorImageInfos
@@ -60,6 +61,7 @@ struct _GskVulkanRender
 
   GskVulkanImage *target;
 
+  GskVulkanBuffer *vertex_buffer;
   VkSampler samplers[3];
   GskVulkanBuffer *storage_buffer;
   guchar *storage_buffer_memory;
@@ -642,6 +644,27 @@ gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
                           0, NULL);
 }
 
+static void
+gsk_vulkan_render_collect_vertex_buffer (GskVulkanRender *self)
+{
+  gsize n_bytes;
+  guchar *data;
+
+  n_bytes = gsk_vulkan_render_pass_count_vertex_data (self->render_pass, 0);
+  if (n_bytes == 0)
+    return;
+
+  if (self->vertex_buffer && gsk_vulkan_buffer_get_size (self->vertex_buffer) < n_bytes)
+    g_clear_pointer (&self->vertex_buffer, gsk_vulkan_buffer_free);
+
+  if (self->vertex_buffer == NULL)
+    self->vertex_buffer = gsk_vulkan_buffer_new (self->vulkan, round_up (n_bytes, VERTEX_BUFFER_SIZE_STEP));
+
+  data = gsk_vulkan_buffer_map (self->vertex_buffer);
+  gsk_vulkan_render_pass_collect_vertex_data (self->render_pass, self, data);
+  gsk_vulkan_buffer_unmap (self->vertex_buffer);
+}
+
 void
 gsk_vulkan_render_draw_pass (GskVulkanRender     *self,
                              GskVulkanRenderPass *pass,
@@ -651,6 +674,15 @@ gsk_vulkan_render_draw_pass (GskVulkanRender     *self,
 
   command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
 
+  if (self->vertex_buffer)
+    vkCmdBindVertexBuffers (command_buffer,
+                            0,
+                            1,
+                            (VkBuffer[1]) {
+                                gsk_vulkan_buffer_get_buffer (self->vertex_buffer)
+                            },
+                            (VkDeviceSize[1]) { 0 });
+
   gsk_vulkan_render_pass_draw (pass, self, self->pipeline_layout, command_buffer);
 
   gsk_vulkan_command_pool_submit_buffer (self->command_pool,
@@ -672,6 +704,8 @@ gsk_vulkan_render_draw (GskVulkanRender *self)
 
   gsk_vulkan_render_prepare_descriptor_sets (self);
 
+  gsk_vulkan_render_collect_vertex_buffer (self);
+
   gsk_vulkan_render_draw_pass (self,
                                self->render_pass,
                                self->fence);
@@ -747,6 +781,8 @@ gsk_vulkan_render_free (GskVulkanRender *self)
   
   gsk_vulkan_render_cleanup (self);
 
+  g_clear_pointer (&self->vertex_buffer, gsk_vulkan_buffer_free);
+
   device = gdk_vulkan_context_get_device (self->vulkan);
 
   g_hash_table_iter_init (&iter, self->pipeline_cache);
index ec54694ce340e688e890859d598813ec78571595..d0b5ec6145e25294e76480c0e800722d427c7bad 100644 (file)
@@ -60,7 +60,6 @@ struct _GskVulkanRenderPass
 
   VkRenderPass render_pass;
   VkFramebuffer framebuffer;
-  GskVulkanBuffer *vertex_data;
 };
 
 struct _GskVulkanParseState
@@ -181,8 +180,6 @@ gsk_vulkan_render_pass_new (GdkVulkanContext      *context,
                                      NULL,
                                      &self->framebuffer);
 
-  self->vertex_data = NULL;
-
 #ifdef G_ENABLE_DEBUG
   if (fallback_pixels_quark == 0)
     {
@@ -219,9 +216,6 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
   vkDestroyFramebuffer (device, self->framebuffer, NULL);
   vkDestroyRenderPass (device, self->render_pass, NULL);
 
-  if (self->vertex_data)
-    gsk_vulkan_buffer_free (self->vertex_data);
-
   g_free (self);
 }
 
@@ -241,12 +235,6 @@ gsk_vulkan_render_pass_print (GskVulkanRenderPass *self,
     }
 }
 
-static inline gsize
-round_up (gsize number, gsize divisor)
-{
-  return (number + divisor - 1) / divisor * divisor;
-}
-
 gpointer
 gsk_vulkan_render_pass_alloc_op (GskVulkanRenderPass *self,
                                  gsize                size)
@@ -1422,13 +1410,12 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
     }
 }
 
-static gsize
-gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
+gsize
+gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self,
+                                          gsize                n_bytes)
 {
   GskVulkanOp *op;
-  gsize n_bytes;
 
-  n_bytes = 0;
   for (op = gsk_vulkan_render_pass_get_first_op (self); op; op = op->next)
     {
       n_bytes = gsk_vulkan_op_count_vertex_data (op, n_bytes);
@@ -1437,7 +1424,7 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
   return n_bytes;
 }
 
-static void
+void
 gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
                                             GskVulkanRender     *render,
                                             guchar              *data)
@@ -1450,28 +1437,6 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
     }
 }
 
-static GskVulkanBuffer *
-gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
-                                        GskVulkanRender     *render)
-{
-  if (self->vertex_data == NULL)
-    {
-      gsize n_bytes;
-      guchar *data;
-
-      n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
-      if (n_bytes == 0)
-        return NULL;
-
-      self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
-      data = gsk_vulkan_buffer_map (self->vertex_data);
-      gsk_vulkan_render_pass_collect_vertex_data (self, render, data);
-      gsk_vulkan_buffer_unmap (self->vertex_data);
-    }
-
-  return self->vertex_data;
-}
-
 void
 gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
                                                 GskVulkanRender     *render)
@@ -1493,20 +1458,8 @@ gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass     *self,
   VkPipeline current_pipeline = VK_NULL_HANDLE;
   const GskVulkanOpClass *current_pipeline_class = NULL;
   const char *current_pipeline_clip_type = NULL;
-  GskVulkanBuffer *vertex_buffer;
   GskVulkanOp *op;
 
-  vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
-
-  if (vertex_buffer)
-    vkCmdBindVertexBuffers (command_buffer,
-                            0,
-                            1,
-                            (VkBuffer[1]) {
-                                gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                            },
-                            (VkDeviceSize[1]) { 0 });
-
   for (op = gsk_vulkan_render_pass_get_first_op (self); op; op = op->next)
     {
       if (op->op_class->shader_name &&
index 3040ce624cdf7c87d421b48afb9f926231575758..4168ca746f1a5b6bbb9f8958491e6a6a910f304c 100644 (file)
@@ -33,6 +33,11 @@ void                    gsk_vulkan_render_pass_upload                   (GskVulk
                                                                          GskVulkanUploader      *uploader);
 void                    gsk_vulkan_render_pass_reserve_descriptor_sets  (GskVulkanRenderPass    *self,
                                                                          GskVulkanRender        *render);
+gsize                   gsk_vulkan_render_pass_count_vertex_data        (GskVulkanRenderPass    *self,
+                                                                         gsize                   n_bytes);
+void                    gsk_vulkan_render_pass_collect_vertex_data      (GskVulkanRenderPass    *self,
+                                                                         GskVulkanRender        *render,
+                                                                         guchar                 *data);
 void                    gsk_vulkan_render_pass_draw                     (GskVulkanRenderPass    *self,
                                                                          GskVulkanRender        *render,
                                                                          VkPipelineLayout        pipeline_layout,